/**
	************************************************************
	************************************************************
	************************************************************
	*	文件名： 	lcd1602.c
	*
	*	作者： 		Sunnycee
	*
	*	日期： 		2020-03-02
	*
	*	版本： 		V1.0
	*
	*	说明： 		LCD1602驱动程序
	*
	*	修改记录：	
	************************************************************
	************************************************************
	************************************************************
**/
#include "lcd1602.h"
#include "stm32f10x.h"
#include "delay.h"

/*
************************************************************
*	函数名称：	LCD1602_Send_Byte
*
*	函数功能：	向LCD1602发送字节的部分操作
*
*	入口参数：	data：发送的数据
*
*	返回参数：	无
*
*	说明：	 无
************************************************************
*/
void LCD1602_Send_Byte(u8 data)
{
	u16 temp, temp1;  //temp存取PB值，temp1存取PC值
	temp = GPIOB->ODR;  //读取PB 原IO状态
	temp &= ~(0x001F<<5);
	temp1 = GPIOC->ODR;
	temp1 &= (~0x0007);  //清除0-2位
	temp |= ((u16)data&0x001F)<<5;  //取低5位，因为对应PB 5-9位，所以左移5
	temp1 |= ((u16)data&0x00E0)>>5; 
	GPIOB->ODR = temp;
	GPIOC->ODR = temp1;
	
	delay_us(10);
}


/*
************************************************************
*	函数名称：	LCD1602_Write_Byte
*
*	函数功能：	向LCD1602写入的数据
*
*	入口参数：	data：需要写入的数据
*
*	返回参数：	无
*
*	说明：	 无
************************************************************
*/
void LCD1602_Write_Byte(u8 data)
{
	RS_H;
	RW_L;
	LCD1602_Send_Byte(data);
	E_H;
	delay_us(20);
	E_L;
	delay_us(5);
}


/*
************************************************************
*	函数名称：	LCD1602_Write_Order
*
*	函数功能：	向LCD1602写命令
*
*	入口参数：	flag：忙检测标志  order：需要写入的命令
*
*	返回参数：	无
*
*	说明：	 无
************************************************************
*/
void LCD1602_Write_Order(u8 flag, u8 order)  //flag:0-不忙检测，1-忙检测
{
	if(flag==0)
	{
		RS_L;
		RW_L;
		LCD1602_Send_Byte(order);
		E_H;
		delay_us(20);
		E_L;
		delay_us(5);
	}
	else
	{
		delay_ms(10);  //防止LCD处于忙状态
		RS_L;
		RW_L;
		LCD1602_Send_Byte(order);
		E_H;
		delay_us(20);
		E_L;
		delay_us(5);
	}
}


/*
************************************************************
*	函数名称：	LCD1602_Write_String
*
*	函数功能：	向LCD1602写入字符串
*
*	入口参数：	s[]：需要显示的字符串
*
*	返回参数：	无
*
*	说明：	 LCD1602从第一行第一列开始显示，自动换行
************************************************************
*/
void LCD1602_Write_String(char s[])
{
	u8 i=0;
	LCD1602_Write_Order(1, 0x80);
	while(s[i] != '\0')
	{
		LCD1602_Write_Byte(s[i]);
		if(i==15)
			LCD1602_Write_Order(1, 0xC0);
		i++;
	}
}


/*
************************************************************
*	函数名称：	LCD1602_Init
*
*	函数功能：	LCD1602初始化
*
*	入口参数：	无
*
*	返回参数：	无
*
*	说明：	 无
************************************************************
*/
void LCD1602_Init(void)
{
	//初始化IO口
	RCC->APB2ENR |= (1<<3)|(1<<4)|1|(1<<2);  //使能PB PC PA时钟，以及复用时钟

	AFIO->MAPR &= 0xF8FFFFFF;  //清除JTAG配置信息
	AFIO->MAPR |= 0x02000000;  //关闭JTAG，开启SW
	
	GPIOC->CRL &= 0xF0FFF000;
	GPIOC->CRL |= 0x03000333;  //设置0-2 和RS 推挽输出 50MHz
	GPIOB->CRL &= 0x0000FFFF;
	GPIOB->CRL |= 0x33330000;  //E 和 数据口
	GPIOB->CRH &= 0xFFFFFF00;
	GPIOB->CRH |= 0x00000033;
	GPIOA->CRH &= 0xFFFF0FFF;
	GPIOA->CRH |= 0x00003000;
	
	//初始化LCD
	delay_ms(15);
	LCD1602_Write_Order(0, 0x38);
	delay_ms(5);
	LCD1602_Write_Order(0, 0x38);
	delay_ms(5);
	LCD1602_Write_Order(0, 0x38);
	LCD1602_Write_Order(1, 0x38);
	LCD1602_Write_Order(1, 0x08);
	LCD1602_Write_Order(1, 0x01);
	LCD1602_Write_Order(1, 0x06);
	LCD1602_Write_Order(1, 0x0C);
	
	E_L;
}


/*
************************************************************
*	函数名称：	LCD1602_CGRAM_Write
*
*	函数功能：	向CGRAM写入数据
*
*	入口参数：	cgram_data[]：需要自定义的字符数组
*
*	返回参数：	无
*
*	说明：	 写入自定义字符
************************************************************
*/
void LCD1602_CGRAM_Write(u8 cgram_data[])
{
	u8 i;
	
	LCD1602_Write_Order(1, 0x06);
	LCD1602_Write_Order(1, 0x40);
	
	for(i=0;i<64;i++)
	{
		LCD1602_Write_Byte(cgram_data[i]);
	}
}

